package org.springframework.cloud.openfeign;


import feign.Contract;
import feign.Feign;
import feign.Logger;
import feign.codec.Decoder;
import feign.codec.Encoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class DynamicFeignProxy<T> implements MethodInterceptor {

    DynamicFeginClientFactoryBean factoryBean;
    private Map<String, Object> clientsMap = new HashMap<>();

    public DynamicFeignProxy(DynamicFeginClientFactoryBean dynamicFeginClientFactoryBean) {
        factoryBean = dynamicFeginClientFactoryBean;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        Object client = getClient();
        log.info("开始");
        Object o1 = method.invoke(client, objects);
        log.info(o1.toString());
        log.info("结束");
        return o1;
    }

    public Object getClient() throws Exception {
        IServerSelector iServerSelector = factoryBean.getApplicationContext().getBean(IServerSelector.class);
        String serverUrl = factoryBean.getName();
        if (iServerSelector != null) {
            serverUrl = iServerSelector.getServerUrl(factoryBean.getName());
        }
        if (!StringUtils.hasText(serverUrl)) {
            serverUrl = factoryBean.getName();
        }
        if (!clientsMap.containsKey(serverUrl)) {
            clientsMap.put(serverUrl, createClient(serverUrl));
        }
        return clientsMap.get(serverUrl);
    }

    private Object createClient(String serverUrl) throws Exception {
        if (serverUrl.equals(factoryBean.getName())) {
            Object object = factoryBean.getSuperClient();
            return object;
        }
        return createUrlClient(serverUrl);
    }


    Object createUrlClient(String serverUrl) {
        FeignContext context = factoryBean.getApplicationContext().getBean(FeignContext.class);
        FeignLoggerFactory loggerFactory = factoryBean.get(context, FeignLoggerFactory.class);
        Logger logger = loggerFactory.create(factoryBean.getType());
        // TODO: 2021/8/24 这个地方不要用 factoryBean.get(context, Feign.Builder.class)
        //  使用这个在会默认创建 负载均衡的客户端，会有问题具体原因需进一步了解
        Feign.Builder builder = Feign.builder();       // factoryBean.get(context, Feign.Builder.class);
        builder.logger(logger);
        builder.encoder(factoryBean.get(context, Encoder.class));
        builder.decoder(factoryBean.get(context, Decoder.class));
        builder.contract(factoryBean.get(context, Contract.class));
        String url = serverUrl + cleanPath();
        Object target = builder.target(factoryBean.getType(), url);
        return target;
    }

    private String cleanPath() {
        String path = factoryBean.getPath().trim();
        if (StringUtils.hasLength(path)) {
            if (!path.startsWith("/")) {
                path = "/" + path;
            }
            if (path.endsWith("/")) {
                path = path.substring(0, path.length() - 1);
            }
        }
        return path;
    }
}


